package com.cjkj.equipment.handler;

import com.alibaba.fastjson.JSONObject;
import com.cjkj.common.utils.StringUtils;
import com.cjkj.equipment.config.AMQP;
import com.cjkj.equipment.domain.EquipmentMonitorRecords;
import com.cjkj.equipment.domain.EquipmentMonitorRecordsRealtime;
import com.cjkj.equipment.domain.EquipmentUsageRecords;
import com.cjkj.equipment.domain.dto.BraceletDto;
import com.cjkj.equipment.domain.dto.DeviceStatusDto;
import com.cjkj.equipment.service.*;
import com.cjkj.equipment.util.AMQPUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.jms.Message;
import javax.jms.MessageListener;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 多参数监测仪处理类
 */
@Service("tj02Handler")
@Slf4j
public class TJ02Handler implements AMQPService {
    @Resource
    AMQP amqp;

    @Resource
    IEquipmentMonitorRecordsService monitorRecordsService;

    @Resource
    IEquipmentMonitorRecordsRealtimeService monitorRecordsRealtimeService;

    @Resource
    private IEquipmentService equipmentService;

    @Resource
    private IEquipmentUsageRecordsService usageRecordsService;

    @Override
    public void initAmqp() {
        try {
            AMQPUtil.init(amqp.getSmartBraceletConsumerGroupId(), amqp, messageListener);
        }catch (Exception e){
            log.error("初始化连接失败：",e);
        }
    }

    @Override
    public void processMessage(Message message) {
        byte[] body;
        try {
            body = message.getBody(byte[].class);
        } catch (Exception e){
            log.error("processMessage occurs error ", e);
            throw new RuntimeException("数据采集失败：" + e);
        }
        String content = new String(body);
        log.info("===================SmartBraceletHandler============");
        log.info(content);
        log.info("===================SmartBraceletHandler============");
        BraceletDto braceletDto = JSONObject.parseObject(content, BraceletDto.class);
        DeviceStatusDto statusDto = JSONObject.parseObject(content, DeviceStatusDto.class);

        // 正在使用的设备才保存数据
        String deviceName = braceletDto.getDeviceName();
        EquipmentUsageRecords inUse = usageRecordsService.getInUseByEquipmentNo(deviceName);
        if(inUse == null) {
            return ;
        }

        if(StringUtils.isNotBlank(statusDto.getStatus())){
            //更新设备状态
            boolean update = equipmentService.updateEquipmentStatus(statusDto);
            if(update){
                log.info("更新设备状态成功！{}", statusDto.getDeviceName());
            }else {
                log.error("更新设备状态失败！{}", statusDto.getDeviceName());
            }
            return;
        }
        if(braceletDto.getItems() == null){
            log.error("接收到的消息为空！");
            return;
        }

        EquipmentMonitorRecords record = getRecordFromDto(braceletDto);
        if(monitorRecordsService.insertEquipmentMonitorRecords(record) < 1){
            log.error("添加监测记录失败：{}", record);
            return;
        }
        if(!updateNowRecords(record)){
            log.error("更新实时记录失败;data:{}", record);
        }

        statusDto = new DeviceStatusDto();
        statusDto.setDeviceName(record.getEquipmentNo());
        statusDto.setStatus("online");
        statusDto.setTime(record.getCreateTime());
        //更新设备在线状态
        boolean update = equipmentService.updateEquipmentStatus(statusDto);
        if(update){
            log.info("更新设备状态成功！设备名称：{}，时间：{}", statusDto.getDeviceName(), statusDto);
        }else {
            log.error("更新手环状态失败，设备名称：{}，时间：{}", statusDto.getDeviceName(), statusDto);
        }
    }

    private final static ExecutorService executorService = new ThreadPoolExecutor(
            Runtime.getRuntime().availableProcessors(),
            Runtime.getRuntime().availableProcessors() * 2, 60, TimeUnit.SECONDS,
            new LinkedBlockingQueue(50000));

    /**
     * 消费组监听类，有多个消费队列时，根据不同处理方式创建多个消费监听类
     */
    private final MessageListener messageListener = new MessageListener() {
        @Override
        public void onMessage(final Message message) {
            try {
                //1.收到消息之后一定要ACK。
                // 推荐做法：创建Session选择Session.AUTO_ACKNOWLEDGE，这里会自动ACK。
                // 其他做法：创建Session选择Session.CLIENT_ACKNOWLEDGE，这里一定要调message.acknowledge()来ACK。
                // message.acknowledge();
                //2.建议异步处理收到的消息，确保onMessage函数里没有耗时逻辑。
                // 如果业务处理耗时过程过长阻塞住线程，可能会影响SDK收到消息后的正常回调。
                executorService.submit(new Runnable() {
                    @Override
                    public void run() {
                        processMessage(message);
                    }
                });
            } catch (Exception e) {
                log.error("submit task occurs exception ", e);
            }
        }
    };

    /**
     * 更新实时数据表
     */
    private boolean updateNowRecords(EquipmentMonitorRecords record){
        boolean flag;

        EquipmentMonitorRecordsRealtime realtimeData = monitorRecordsRealtimeService.getByProductIdAndEquipmentNo(record.getProductId(), record.getEquipmentNo());
        if(realtimeData == null){
            realtimeData = new EquipmentMonitorRecordsRealtime();
            BeanUtils.copyProperties(record, realtimeData);

            realtimeData.setEquipmentNo(record.getEquipmentNo());
            realtimeData.setProductId(record.getProductId());
            realtimeData.setCreateTime(record.getCreateTime());
            flag = monitorRecordsRealtimeService.insertEquipmentMonitorRecordsRealtime(realtimeData) > 0;
        } else {
            Long id = realtimeData.getId();
            Date createTime = realtimeData.getCreateTime();
            realtimeData = new EquipmentMonitorRecordsRealtime();
            BeanUtils.copyProperties(record, realtimeData);
            realtimeData.setId(id);
            realtimeData.setCreateTime(createTime);
            realtimeData.setUpdateTime(record.getCreateTime());
            flag = monitorRecordsRealtimeService.updateEquipmentMonitorRecordsRealtime(realtimeData) > 0;
        }

        return flag;
    }

    private EquipmentMonitorRecords getRecordFromDto(BraceletDto braceletDto){
        EquipmentMonitorRecords record = new EquipmentMonitorRecords();
        record.setProductId(braceletDto.getIotId());
        record.setEquipmentNo(braceletDto.getDeviceName());

        if(braceletDto.getItems().getWState() != null){
            record.setwState(Integer.parseInt(braceletDto.getItems().getWState().getValue()));
            record.setCreateTime(braceletDto.getItems().getWState().getTime());
        }
        if(braceletDto.getItems().getBatpt() != null){
            record.setBatpt(Integer.parseInt(braceletDto.getItems().getBatpt().getValue()));
            record.setCreateTime(braceletDto.getItems().getBatpt().getTime());
        }
        if(braceletDto.getItems().getSpO2() != null){
            record.setSpo2(Integer.parseInt(braceletDto.getItems().getSpO2().getValue()));
            record.setCreateTime(braceletDto.getItems().getSpO2().getTime());
        }
        if(braceletDto.getItems().getTemperature() != null){
            record.setTemp(Float.parseFloat(braceletDto.getItems().getTemperature().getValue()));
            record.setCreateTime(braceletDto.getItems().getTemperature().getTime());
        }
        if(braceletDto.getItems().getHR() != null){
            record.setHr(Integer.parseInt(braceletDto.getItems().getHR().getValue()));
            record.setCreateTime(braceletDto.getItems().getHR().getTime());
        }
        if(braceletDto.getItems().getFailState() != null){
            record.setRestHeart(Integer.parseInt(braceletDto.getItems().getFailState().getValue()));
            record.setCreateTime(braceletDto.getItems().getFailState().getTime());
        }
        if(braceletDto.getItems().getTsensorState() != null){
            record.setTempSensorStatus(Integer.parseInt(braceletDto.getItems().getTsensorState().getValue()));
            record.setCreateTime(braceletDto.getItems().getTsensorState().getTime());
        }
        return record;
    }
}